<template>
  <el-drawer
    v-model="visible"
    :title="title"
    :size="drawerSize"
    :close-on-click-modal="true"
    :show-close="true"
    destroy-on-close
    @closed="handleClosed"
  >
    <el-form
      ref="formRef"
      :model="formData"
      :rules="rules"
      label-width="120px"
      class="drawer-form"
      @submit.prevent
    >
      <el-scrollbar class="drawer-scrollbar">
        <div class="form-content">
          <el-form-item
            v-for="item in visibleFormConfig"
            :key="item.field"
            :label="item.label"
            :prop="item.field"
            :class="{ 'is-required': item.rules?.some((rule) => rule.required) }"
          >
            <!-- 使用 render 函数渲染 -->
            <template v-if="item.render">
              <component :is="markRaw(item.render(formData, { isEdit: isEdit.value, item }))" />
            </template>

            <!-- Input 输入框 -->
            <template v-else-if="item.component === 'Input'">
              <el-input
                v-model="formData[item.field]"
                :placeholder="item.placeholder"
                :disabled="isEdit && item.editDisabled"
                v-bind="item.props || {}"
              />
            </template>

            <!-- Select 选择器 -->
            <template v-else-if="item.component === 'Select'">
              <el-select
                v-model="formData[item.field]"
                :placeholder="item.placeholder"
                :disabled="isEdit && item.editDisabled"
                v-bind="item.props || {}"
              >
                <el-option
                  v-for="option in item.options"
                  :key="option.value"
                  :label="option.label"
                  :value="option.value"
                />
              </el-select>
            </template>

            <!-- Radio 单选框组 -->
            <template v-else-if="item.component === 'Radio'">
              <el-radio-group
                v-model="formData[item.field]"
                :disabled="isEdit && item.editDisabled"
              >
                <el-radio v-for="option in item.options" :key="option.value" :value="option.value">
                  {{ option.label }}
                </el-radio>
              </el-radio-group>
            </template>

            <!-- Upload 上传组件 -->
            <template v-else-if="item.component === 'Upload'">
              <component :is="ElUpload" v-bind="item.props || {}" v-on="item.on || {}">
                <template #default>
                  <slot :name="`upload-${item.field}`">
                    <el-button type="primary">点击上传</el-button>
                  </slot>
                </template>
                <template #tip>
                  <slot :name="`upload-tip-${item.field}`">
                    <div class="el-upload__tip">{{ item.tip }}</div>
                  </slot>
                </template>
              </component>
            </template>

            <!-- 其他组件 -->
            <template v-else>
              <component
                :is="item.component"
                v-model="formData[item.field]"
                :placeholder="item.placeholder"
                :disabled="isEdit && item.editDisabled"
                v-bind="item.props || {}"
              />
            </template>
          </el-form-item>
        </div>
      </el-scrollbar>
    </el-form>

    <template #footer>
      <div class="drawer-footer">
        <el-button @click="visible = false">取 消</el-button>
        <el-button type="primary" :loading="loading" @click="handleSubmit"> 确 定 </el-button>
      </div>
    </template>
  </el-drawer>
</template>

<script setup>
import { ref, reactive, computed, watch, onMounted, onUnmounted, markRaw } from 'vue'
import { ElMessage, ElUpload } from 'element-plus'

/**
 * Props定义
 * @typedef {Object} FormConfig
 * @property {string} field - 字段名
 * @property {string} label - 标签文本
 * @property {string} component - 组件类型
 * @property {string} [placeholder] - 占位文本
 * @property {Object} [props] - 组件属性
 * @property {boolean} [editDisabled] - 编辑时是否禁用
 * @property {boolean} [hideInEdit] - 编辑时是否隐藏
 * @property {Array} [options] - 选项数据(用于Select/Radio等)
 * @property {Object} [rules] - 验证规则
 * @property {Function} [showCondition] - 条件显示函数，接收formData参数，返回boolean
 */
const props = defineProps({
  // 控制抽屉显示
  modelValue: {
    type: Boolean,
    required: true,
  },
  // 抽屉标题
  title: {
    type: String,
    default: '表单',
  },
  // 表单数据(编辑时传入)
  data: {
    type: Object,
    default: () => ({}),
  },
  // 表单配置
  formConfig: {
    type: Array,
    required: true,
  },
  // 默认表单数据
  defaultFormData: {
    type: Object,
    required: true,
  },
})

/**
 * Emits定义
 */
const emit = defineEmits(['update:modelValue', 'success'])

/**
 * Refs
 */
const formRef = ref(null)
const loading = ref(false)

/**
 * 计算属性
 */
// 是否编辑模式
const isEdit = computed(() => Boolean(props.data?.id))

// 抽屉可见性
const visible = computed({
  get: () => props.modelValue,
  set: (val) => emit('update:modelValue', val),
})

// 验证规则
const rules = computed(() => {
  return props.formConfig.reduce((acc, item) => {
    if (item.rules) {
      acc[item.field] = item.rules
    }
    return acc
  }, {})
})

// 根据编辑状态和条件过滤表单配置
const visibleFormConfig = computed(() => {
  return props.formConfig.filter((item) => {
    // 编辑模式下，过滤掉需要隐藏的字段
    if (isEdit.value && item.hideInEdit) {
      return false
    }
    // 条件显示：如果定义了showCondition函数，则根据条件决定是否显示
    if (item.showCondition && typeof item.showCondition === 'function') {
      return item.showCondition(formData)
    }
    return true
  })
})

/**
 * 响应式数据
 */
// 表单数据
const formData = reactive({ ...props.defaultFormData })

// 窗口宽度(用于响应式)
const windowWidth = ref(window.innerWidth)

/**
 * 计算抽屉宽度
 */
const drawerSize = computed(() => {
  return windowWidth.value < 768 ? '100%' : '600px'
})

/**
 * 监听窗口大小变化
 */
const handleResize = () => {
  windowWidth.value = window.innerWidth
}

/**
 * 生命周期钩子
 */
onMounted(() => {
  window.addEventListener('resize', handleResize)
})

onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
})

/**
 * 监听data变化，更新表单数据
 */
watch(
  () => props.data,
  (newData) => {
    // 重置表单数据到初始状态
    Object.assign(formData, props.defaultFormData)
    // 更新新的数据
    if (newData) {
      for (const key in formData) {
        if (key in newData) {
          formData[key] = newData[key]
        }
      }
    }
  },
  { immediate: true, deep: true },
)

/**
 * 方法定义
 */
// 提交处理
const handleSubmit = async () => {
  try {
    // 表单验证
    await formRef.value?.validate()
    loading.value = true

    // 触发成功事件
    emit('success', { ...formData })
    visible.value = false
  } catch (error) {
    console.error('表单提交失败:', error)
  } finally {
    loading.value = false
  }
}

// 关闭处理
const handleClosed = () => {
  // 重置表单验证状态
  formRef.value?.resetFields()
  // 重置表单数据
  Object.assign(formData, props.defaultFormData)
}
</script>

<style lang="scss" scoped>
.drawer-form {
  height: 100%;
  padding: 0;
  overflow: hidden;

  :deep(.el-form-item) {
    margin-bottom: 24px;

    &.is-required .el-form-item__label::before {
      margin-right: 4px;
    }

    .el-form-item__label {
      font-weight: 500;
      color: var(--el-text-color-regular);
      padding-right: 12px;
    }

    .el-form-item__content {
      .el-input,
      .el-select,
      .el-radio-group {
        width: 100%;
      }

      .el-input__wrapper,
      .el-textarea__inner {
        box-shadow: 0 0 0 1px var(--el-border-color) inset;

        &:hover {
          box-shadow: 0 0 0 1px var(--el-border-color-hover) inset;
        }

        &.is-focus {
          box-shadow: 0 0 0 1px var(--el-color-primary) inset;
        }
      }

      .el-radio {
        margin-right: 30px;
        .el-radio__label {
          color: var(--el-text-color-regular);
        }
      }
    }

    &.is-error {
      .el-input__wrapper {
        box-shadow: 0 0 0 1px var(--el-color-danger) inset;
      }
    }
  }
}

.drawer-scrollbar {
  height: calc(100vh - 170px);

  .form-content {
    padding: 24px 24px 32px;
  }
}

.drawer-footer {
  padding: 16px 20px;
  text-align: right;
  border-top: 1px solid var(--el-border-color-lighter);
  background: var(--el-bg-color);

  .el-button {
    min-width: 100px;

    & + .el-button {
      margin-left: 12px;
    }
  }
}

// 暗黑模式适配
:deep(.dark) {
  .drawer-form {
    background: var(--el-bg-color);
  }

  .drawer-footer {
    background: var(--el-bg-color-overlay);
    border-top-color: var(--el-border-color-dark);
  }
}

// 移动端适配
@media screen and (max-width: 768px) {
  .drawer-scrollbar {
    height: calc(100vh - 120px);
  }

  .drawer-footer {
    padding: 12px 16px;

    .el-button {
      min-width: auto;
    }
  }

  :deep(.el-form-item) {
    margin-bottom: 20px;
  }
}
</style>
